/*********************************************
 *TCPClient for ESP8266.
 *Author: openthings@163.com. 
 *copyright&GPL V2.
 *Last modified 2014-10-20.
 **********************************************/

#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "user_interface.h"

#include "version.h"

#include "espconn.h"
#include "user_json.h"
#include "driver/uart.h"

//#if ESP_PLATFORM
#include "xnet_base.h"
//#endif

#include "../xflow/xc_cmd.h"
#include "wix_tcpclient.h"

extern cmd_functionType cmd_fun[xc_cmdNum];
extern void xc_flow_onWifiReceiving(char* strwifi);	//接收到WiFi传来的数据。

//连接句柄，全局共享。
 struct espconn esp_conn_client;

/******************************************************************************
 * FunctionName: user_webserver_init
 * Description: parameter initialize as a server
 * Parameters: port -- server port
 * Returns      	: none
*******************************************************************************/
//建立TCP连接到服务器。
//!内存管理和释放注意！！！
void tcpclient_connect(char* server, uint32 port)
{
	uint32_t ip = 0;
	char temp[32];
	char ipTemp[64];
	int8	nConn= 0;
	
	os_sprintf(temp, "TCPCLIENT TO:%s:%d\r", server, port);
	sendInfoAll(temp);

	strcpy(ipTemp,server);
	ip = ipaddr_addr(ipTemp);

	esp_conn_client.type = ESPCONN_TCP;
    esp_conn_client.state = ESPCONN_NONE;
    espconn_regist_connectcb(&esp_conn_client, tcpclient_connect_cb);

	esp_conn_client.proto.tcp = (esp_tcp *) os_zalloc( sizeof(esp_tcp) );
	os_memcpy(esp_conn_client.proto.tcp->remote_ip, &ip, 4);
	esp_conn_client.proto.tcp->local_port = espconn_port();
	esp_conn_client.proto.tcp->remote_port = port;

	nConn = espconn_connect(&esp_conn_client);
	if (nConn == 0) {
		sendInfoAll("connection ok.");
	} else {
		sendInfoAll("connection fail.");
	}
}

/******************************************************************************
 * FunctionName : tcpclient_recv
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR	 tcpclient_connect_cb(void *arg)
{
    struct espconn *pesp_conn = arg;
	
	//Install TCP/IP receiver.
    espconn_regist_reconcb(pesp_conn, tcpclient_recon);
    espconn_regist_recvcb(pesp_conn, tcpclient_recv);
	//espconn_regist_sentcb(pespconn, tcpclient_sent_cb);
    espconn_regist_disconcb(pesp_conn, tcpclient_discon);
}

/******************************************************************************
 * FunctionName : tcpclient_recv
 * Description  : Processing the received data from the server
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
tcpclient_recv(void *arg, char *pusrdata, unsigned short length)
{
	pusrdata[length] = '\0';
	xc_flow_onWifiReceiving(pusrdata);
}

/******************************************************************************
 * FunctionName : tcpclient_send
 * 发送数据到WiFi端口，比如从串口来的数据实现透传。
 * Description  : Send data to wifi channel.
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR	
tcpclient_send(char *pbuf, unsigned short length)
{
	//struct espconn *pesp_conn = arg;

//#ifdef SERVER_SSL_ENABLE
//        espconn_secure_sent(&esp_conn, pbuf, length);
//#else
	espconn_sent(&esp_conn_client, pbuf, length);
//#endif
}

/******************************************************************************
 * FunctionName : webserver_recon
 * Description  : the connection has been err, reconnection
 * Parameters   : arg -- Additional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
ICACHE_FLASH_ATTR	void
tcpclient_recon(void *arg, sint8 err)
{
    struct espconn *pesp_conn = arg;

    os_printf("webserver's %d.%d.%d.%d:%d err %d reconnect\n", pesp_conn->proto.tcp->remote_ip[0],
    		pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2],
    		pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port, err);
}

/******************************************************************************
 * FunctionName : tcpclient_recon
 * Description  : the connection has been err, reconnection
 * Parameters   : arg -- Additional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
ICACHE_FLASH_ATTR	void 
tcpclient_discon(void *arg)
{
	if (esp_conn_client.type == ESPCONN_TCP) {
		//specialAtState = FALSE;
		espconn_disconnect(&esp_conn_client);
	} else{
		os_free(esp_conn_client.proto.udp);
		sendInfoAll("disconnect. \r");
		//mdState = m_unlink;
		//uart0_sendStr("Unlink\r\n");
	}

    os_printf("tcpclient's %d.%d.%d.%d:%d disconnect\n", 
				esp_conn_client.proto.tcp->remote_ip[0],
				esp_conn_client.proto.tcp->remote_ip[1],
				esp_conn_client.proto.tcp->remote_ip[2],
        		esp_conn_client.proto.tcp->remote_ip[3],
				esp_conn_client.proto.tcp->remote_port);
}

/*******************************************************
 * 列出连接IP服务器的客户端IP。
  * @brief  Execution commad of get link status.
  * @param  id: commad id number
  * @retval None
  ******************************************************/
void ICACHE_FLASH_ATTR xc_cmd_CIPCLIENTQ(uint8_t id, char *pParam)
{
	char temp[64];
	uint8_t i;

	if (esp_conn_client.proto.tcp==NULL) {
		sendInfoAll("remote not connected.");
	} else {
		os_sprintf(temp, "%s: %d.%d.%d.%d,%d\r\n",cmd_fun[id].cmdName,
				IP2STR(esp_conn_client.proto.tcp->remote_ip),
				esp_conn_client.proto.tcp->remote_port);				   
		sendInfoAll(temp);
	}
}

/*******************************************************
  * @brief  Setup commad of start client.
  * @param  id: commad id number
  * @param  pParam: AT input param
  * @retval None
  ******************************************************/
void ICACHE_FLASH_ATTR xc_cmd_CIPCLIENT(uint8_t id, char *pParam)
{
	uint32 port;

	char delims[] = ",";
	char *ipAddr =  strtok( NULL, delims );
	char *ipPort =  strtok( NULL, delims );

	if (wifi_station_get_connect_status() != STATION_GOT_IP)	{
		sendInfoAll("Invalid IP, may AP error.\r");
		return;
	}

	//解析域名到IP.
// 	if ((ip == 0xffffffff) && (os_memcmp(ipTemp,"255.255.255.255",16) != 0))	{
// 		//espconn_gethostbyname(pLink[linkID].pCon, ipTemp, &host_ip, at_dns_found);
// 	} else {
// 	}
	
	if (strlen(ipAddr) < 7)	{
		sendInfoAll("IP invalid.\r");
		return;
	}
	port = atoi(ipPort);
	tcpclient_connect(ipAddr, port);
}

/*******************************************************
  * @brief  commad of close ip link.
  * @param  id: commad id number
  * @param  pParam: AT input param
  * @retval None
  ******************************************************/
void ICACHE_FLASH_ATTR xc_cmd_CIPCLOSE(uint8_t id, char *pParam)
{	
	//  if(mdState == m_linked)
	//  {
	tcpclient_discon(NULL);
	//
	//  }	
	//  specialAtState = FALSE;
}

/**End of TCPClient************************************************************/

